package classign.election.kingvar.come.electionclasssign.api;

import android.support.annotation.NonNull;
import android.util.Log;

import com.orhanobut.logger.Logger;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.concurrent.TimeUnit;

import classign.election.kingvar.come.electionclasssign.activity.MyApplication;
import classign.election.kingvar.come.electionclasssign.api.exception.RetryWhenNetworkException;
import classign.election.kingvar.come.electionclasssign.api.info.AllProjectInfo;
import classign.election.kingvar.come.electionclasssign.api.info.AllStudentInfo;
import classign.election.kingvar.come.electionclasssign.api.info.AttendanceInfo;
import classign.election.kingvar.come.electionclasssign.api.info.BaseClassInfo;
import classign.election.kingvar.come.electionclasssign.api.info.ClassGrowthRingInfo;
import classign.election.kingvar.come.electionclasssign.api.info.ClassHonorInfo;
import classign.election.kingvar.come.electionclasssign.api.info.ClassInfo;
import classign.election.kingvar.come.electionclasssign.api.info.EncourageTalkInfo;
import classign.election.kingvar.come.electionclasssign.api.info.HeartbeatCmd;
import classign.election.kingvar.come.electionclasssign.api.info.ProClassAndSchoolNotice;
import classign.election.kingvar.come.electionclasssign.api.info.ProClassSchedule;
import classign.election.kingvar.come.electionclasssign.api.info.ProIsCodeSuccess;
import classign.election.kingvar.come.electionclasssign.api.info.ProMessageContent;
import classign.election.kingvar.come.electionclasssign.api.info.ProMyDream;
import classign.election.kingvar.come.electionclasssign.api.info.ProTemperature;
import classign.election.kingvar.come.electionclasssign.api.info.ProToadyStar;
import classign.election.kingvar.come.electionclasssign.api.info.RewardInfo;
import classign.election.kingvar.come.electionclasssign.api.info.ThisWeekDutyInfo;
import classign.election.kingvar.come.electionclasssign.api.info.ThisWeekProjectInfo;
import classign.election.kingvar.come.electionclasssign.api.info.TitleInfo;
import classign.election.kingvar.come.electionclasssign.api.info.TodayDeYuInfo;
import classign.election.kingvar.come.electionclasssign.api.info.TodayDutyInfo;
import classign.election.kingvar.come.electionclasssign.api.info.VersionUpdateInfo;
import classign.election.kingvar.come.electionclasssign.base.BaseProtocol;
import classign.election.kingvar.come.electionclasssign.tools.utils.NetUtil;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Created by long on 2016/8/22.
 * 整个网络通信服务的启动控制，必须先调用初始化函数才能正常使用网络通信接口
 */
public class RetrofitService {


    //设缓存有效期为1天
    static final long CACHE_STALE_SEC = 60 * 60 * 24 * 1;
    //查询缓存的Cache-Control设置，为if-only-cache时只查询缓存而不会请求服务器，max-stale可以配合设置缓存失效时间
    private static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC;
    //查询网络的Cache-Control设置
    //(假如请求了服务器并在a时刻返回响应结果，则在max-age规定的秒数内，浏览器将不会发送对应的请求到服务器，数据由缓存直接返回)
    static final String CACHE_CONTROL_NETWORK = "Cache-Control: public, max-age=60";
    // 避免出现 HTTP 403 Forbidden，参考：http://stackoverflow.com/questions/13670692/403-forbidden-with-java-but-not-web-browser
    static final String AVOID_HTTP403_FORBIDDEN = "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11";

    private static final String NEWS_HOST = BaseProtocol.HOST_BASE;
    private static final String WELFARE_HOST = BaseProtocol.LocationInfo;
    private static final String KAO_QIN_HOST = BaseProtocol.KAO_QIN;
    private static final String TAG = "RetrofitService";

    private static INewsApi sNewsService;
    private static ProjectApi projectApi;
    private static   KaoqinApi  kaoqinApi;


    private RetrofitService() {
        throw new AssertionError();
    }

    /**
     * 初始化网络通信服务
     */
    public static void init() {
        File file = new File(MyApplication.getInstance().getCacheDir(), "HttpCache");
        if (!file.exists()) {
            file.mkdirs();
        }
        Log.i(TAG, "init: file.exists() = " + file.exists());
        // 指定缓存路径,缓存大小100Mb
        Cache cache = new Cache(file,
                1024 * 1024 * 100);
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .cache(cache)
                .retryOnConnectionFailure(true)
                .connectTimeout(20, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .writeTimeout(20, TimeUnit.SECONDS)
                .addInterceptor(sRewriteCacheControlInterceptor)
                .addNetworkInterceptor(sRewriteCacheControlInterceptor)
                .addInterceptor(sLoggingInterceptor)
                .build();

        Retrofit retrofit = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(NEWS_HOST)
                .build();
        sNewsService = retrofit.create(INewsApi.class);
        Retrofit retrofit_ = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(WELFARE_HOST)
                .build();
        projectApi = retrofit_.create(ProjectApi.class);
        Retrofit retrofit_kaoqin = new Retrofit.Builder()
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .baseUrl(KAO_QIN_HOST)
                .build();
        kaoqinApi = retrofit_kaoqin.create(KaoqinApi.class);
    }

    /**
     * 云端响应头拦截器，用来配置缓存策略
     * Dangerous interceptor that rewrites the server's cache-control header.
     */
    private static final Interceptor sRewriteCacheControlInterceptor = new Interceptor() {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            if (!NetUtil.isNetworkAvailable(MyApplication.getInstance()) || !NetUtil.isWifiConnected(MyApplication.getInstance())) {
                request = request.newBuilder()
                        .removeHeader("Pragma")
                        .cacheControl(CacheControl.FORCE_CACHE)
                        .build();
                Logger.e("no network");
                return chain.proceed(request);
            }
            Response response = chain.proceed(request);
            Response responseLatest;
            if (NetUtil.isNetworkAvailable(MyApplication.getInstance()) || NetUtil.isWifiConnected(MyApplication.getInstance())) {
                //有网的时候读接口上的@Headers里的配置，你可以在这里进行统一的设置
                String cacheControl = request.cacheControl().toString();
                responseLatest = response.newBuilder()
                        .header("Cache-Control", cacheControl)
                        .removeHeader("Pragma")
                        .build();
            } else {
                responseLatest = response.newBuilder()
                        .header("Cache-Control", "public, " + CACHE_CONTROL_CACHE)
                        .removeHeader("Pragma")
                        .build();
            }
            return responseLatest;
        }
    };

    /**
     * 打印返回的json数据拦截器
     */
    private static final Interceptor sLoggingInterceptor = new Interceptor() {

        @Override
        public Response intercept(Chain chain) throws IOException {
            final Request request = chain.request();
            Buffer requestBuffer = new Buffer();
            if (request.body() != null) {
                request.body().writeTo(requestBuffer);
            } else {
                Logger.d("LogTAG", "request.body() == null");
            }
            //打印url信息
            Logger.w(request.url() + (request.body() != null ? "?" + _parseParams(request.body(), requestBuffer) : ""));
            final Response response = chain.proceed(request);
            return response;
        }
    };

    @NonNull
    private static String _parseParams(RequestBody body, Buffer requestBuffer) throws UnsupportedEncodingException {
        if (body.contentType() != null && !body.contentType().toString().contains("multipart")) {
            return URLDecoder.decode(requestBuffer.readUtf8(), "UTF-8");
        }
        return "null";
    }

    /************************************ API *******************************************/


    /**
     * 获取心跳信息
     *
     * @return
     */
    public static Observable<HeartbeatCmd> getHeartbeatCmd(String imei) {
        if (imei==null){
            imei = "";
        }
        return sNewsService.getHeartbeatCmd(imei)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());



    }

    /**
     * 获取班级基本信息(登陆)
     *
     * @return
     */
    public static Observable<BaseClassInfo> getBaseClassInfo(String imei) {
        return sNewsService.getBaseClassInfo(imei)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取班级学生信息(保存数据库)
     *
     * @return
     */
    public static Observable<AllStudentInfo> getAllStudentInfo(String classid) {
        return sNewsService.getAllStudentInfo(classid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }
    /**
     * 获取主页考勤打卡信息
     *
     * @return
     */
    public static Observable<TodayDeYuInfo> getTodayDeYuInfo(String classid) {
        return kaoqinApi.getTodayDeYuInfo(classid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取考勤信息
     *
     * @return
     */

    public static Observable<AttendanceInfo> getAttendanceRecorder(String mClsid, String mTid) {
        return sNewsService.getNewsList(mClsid, mTid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取考勤标题
     *
     * @param schoolid
     * @return
     */

    public static Observable<TitleInfo> getTitleInfo(String schoolid, String clsid) {
        return sNewsService.getAttendance(schoolid, clsid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取版本更新相关信息
     *
     * @return
     */
    public static Observable<VersionUpdateInfo> getVersionUpdateInfo() {
        return sNewsService.getVersionInfo()
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取今日值日相关信息
     *
     * @return
     */
    public static Observable<TodayDutyInfo> getTodayDutyInfo(String classid) {
        return sNewsService.getTodayDutyInfo(classid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取本周值日相关信息
     *
     * @return
     */
    public static Observable<ThisWeekDutyInfo> getThisWeekDutyInfo(String classid) {
        return sNewsService.getThisWeekDutyInfo(classid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取本周课程相关信息
     *
     * @return
     */
    public static Observable<ThisWeekProjectInfo> getThisWeekProjectInfo(String classid) {
        return sNewsService.getThisWeekProjectInfo(classid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取班级荣誉信息
     *
     * @return
     */

    public static Observable<ClassHonorInfo> getClassHonorInfo(String mClsid) {
        return sNewsService.getClassHonor(mClsid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取班级年轮信息
     *
     * @return
     */

    public static Observable<ClassGrowthRingInfo> getClassGrowthRingInfo(String mClsid) {
        return sNewsService.getClassGrowthRing(mClsid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取班级风采信息
     *
     * @return
     */

    public static Observable<ClassInfo> getClassInfo(String mClsid) {
        return sNewsService.getClassInfo(mClsid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取班级和校园奖项信息
     *
     * @return
     */

    public static Observable<RewardInfo> getRewardInfo(String mType, String mStudentid) {
        return sNewsService.getRewardInfo(mType, mStudentid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取鼓励的话信息
     *
     * @return
     */

    public static Observable<EncourageTalkInfo> getEncourageInfo(String mStudentid) {
        return sNewsService.getEncourageInfo(mStudentid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取今日之星
     *
     * @return
     */

    public static Observable<ProToadyStar> getTodayStarInfo(String mClassid) {
        return sNewsService.getTodayStarInfo(mClassid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取我的梦想
     *
     * @return
     */

    public static Observable<ProMyDream> getMyDreamInfo(String mStudentid) {
        return sNewsService.getMyDreamInfo(mStudentid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }


    /**
     * 获取班级和学校通知的信息
     *
     * @return
     */
    public static Observable<ProClassAndSchoolNotice> getNoticeInfo(String mClassid, String mSchoolid) {
        return sNewsService.getNoticeInfo(mClassid, mSchoolid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取班级日程管理信息
     *
     * @return
     */
    public static Observable<ProClassSchedule> getClassSchedule(String mClassid) {
        return sNewsService.getClassSchedule(mClassid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取当前气温和天气
     *
     * @return
     */
    public static Observable<ProTemperature> getCurrentTemprature(String location) {
        return projectApi.getTemperatureInfo(location)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());

    }

    /**
     * 获取全部课程信息
     *
     * @return
     */

    public static Observable<AllProjectInfo> getProjectInfo(String mClsid) {
        return sNewsService.getAllProject(mClsid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());
    }

    public static Observable.Transformer schedulersTransformer() {
        return observable -> ((Observable) observable)
                .retryWhen(new RetryWhenNetworkException())
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread());
    }

    public static Observable<ProMessageContent> getMessageContent(int studentid) {
        return sNewsService.getMessageContent(studentid)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());
    }

    public static Observable<ProIsCodeSuccess> sendMessageContent(int studentId, int messagetID, String content) {
       return sNewsService.sendMessageContent(studentId,messagetID,content)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());
    }

    public static Observable<ProIsCodeSuccess> postUpLoadData(String imei, String schoolid, String date, String data) {
        return kaoqinApi.postUpLoadData(imei,schoolid,date,data)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(AndroidSchedulers.mainThread())
                .retryWhen(new RetryWhenNetworkException());
    }
}
